﻿using System;
using System.Linq;
using System.ServiceModel;
using RadaCode.SwissKnife.Random;
using RadaCode.SwissKnife.Search.Providers.Bing;

namespace RadaCode.SwissKnife.Search
{
    public class BingUnitOfWork
    {
        private readonly BingPortTypeClient _bingClient;
        private readonly string _apiKey;

        private readonly RandomWordSearcher _wordSearcher;

        private readonly MersenneTwister _twister;

        private readonly int _exactMaxOffset;

        private SourceType _source;
        private SearchRequest _request;
        private SearchResponse _response;

        public BingUnitOfWork(BingPortTypeClient client, string apiKey, int exactMaxOffset = 30)
        {
            _bingClient = client;
            _apiKey = apiKey;

            _exactMaxOffset = exactMaxOffset;

            _wordSearcher = new RandomWordSearcher();
            _twister = new MersenneTwister();
        }

        #region Search Specific

        public ImageResult[] GetRandomImageResults(int minCount)
        {
            _request = new SearchRequest();
            _source = SourceType.Image;

            ImageResult[] results  = new ImageResult[minCount];

            var words = _wordSearcher.GetRandomWords(minCount);

            for (var i = 0; i < minCount; i++)
            {
                InitializeSearchRequest(words[i], 1);

                try
                {
                    _response = _bingClient.Search(_request);
                }
                catch (ProtocolException)
                {
                    throw new Exception("Bing is out of order again!");
                }

                while (_response.Image.Results == null || results.Contains(_response.Image.Results.First()))
                {
                    InitializeSearchRequest(_wordSearcher.GetRandomWord(), 1);
                    _response = _bingClient.Search(_request);
                }

                results[i] = _response.Image.Results.FirstOrDefault();
            }

            return results;
        }

        public ImageResult[] GetExactImageResults(string keyword, int minCount)
        {
            _request = new SearchRequest();
            _source = SourceType.Image;

            ImageResult[] results;

            InitializeSearchRequest(keyword, minCount);

            _response = _bingClient.Search(_request);

            results = _response.Image.Results;

            return results;
        }

        private bool ResultsAreNotOk(ImageResult[] results, int minCount)
        {
            if (results == null) return true;
            return results.Count() < minCount;
        }

        private void InitializeSearchRequest(string searchstring, int count)
        {
            _request.Adult = AdultOption.Strict;
            _request.AdultSpecified = true;
            _request.AppId = _apiKey;
            _request.Query = searchstring;
            _request.Sources = new SourceType[] { this._source };
            _request.Version = "2.0";

            _request.Image = new ImageRequest
                                 {
                                     Filters = new string[] {"Aspect:Square", "Size:Small"},
                                     Count = (uint)count,
                                     CountSpecified = true,
                                     Offset = (uint)_twister.Next(_exactMaxOffset),
                                     OffsetSpecified = true
                                 };
        }

        #endregion
    }
}
